using System;
using System.Xml;
using System.Runtime.Serialization;
using System.Text;
using System.IO;

namespace Ro.Norc.ServiceStackClient
{
	/// <summary>
	/// The standard XML encoder/decoder
	/// </summary>
	public class ServiceEncoderXml : ServiceEncoderBase
	{
		/// <summary>
		/// Creates a new ServiceEncodeXml instance
		/// </summary>
		public ServiceEncoderXml() : this("xml")
		{
			return;
		}
		
		/// <summary>
		/// Creates a new ServiceEncodeXml instance
		/// </summary>
		/// <param name='endpointPart'>
		/// The string that is automatically appended to the URL by the Service class, should this behaviour be enabled
		/// </param>
		public ServiceEncoderXml(string endpointPart) : base()
		{
			if (string.IsNullOrEmpty(endpointPart)) {
				endpointPart = "xml";
			}
			_allowedTypes = new string[] {
				"application/xml",
				"text/xml"
			};
			_contentType = "application/xml";
			_endpointPart = endpointPart;
		}
		
		/// <summary>
		/// Encodes a given object to an XML string representation
		/// </summary>
		/// <param name="obj">
		/// The object to encode
		/// </param>
		/// <returns>
		/// The resulting XML string representation
		/// </returns>
		public override string Encode (object obj)
		{
			if (obj == null) {
				return null;
			}
			DataContractSerializer _ser = null;
			StringBuilder _sb = new StringBuilder();
			XmlTextWriter _sw = new XmlTextWriter(new StringWriter(_sb));
			string _repr = null;
			
			try
			{
				_ser = new DataContractSerializer(obj.GetType());
				_ser.WriteObject(_sw, obj);
				_repr = _sb.ToString();
			}
			catch(Exception)
			{
				_repr = null;
			}
			
			return _repr;
		}

		/// <summary>
		/// Decodes a given XML string representation to an object of the given type parameter T
		/// </summary>
		/// <param name="repr">
		/// A string representation to be decoded
		/// </param>
		/// <returns>
		/// An object of type T
		/// </returns>
		public override object Decode (string repr, Type t)
		{
			if (string.IsNullOrEmpty(repr)) {
				return null;
			}
			MemoryStream _ms = new MemoryStream();
			DataContractSerializer _ser = null;
			byte[] _bytes = null;
			object _obj = null;

			try 
			{
				_bytes = Encoding.UTF8.GetBytes(repr);
				_ms.Write(_bytes, 0, _bytes.Length);
				_ser = new DataContractSerializer(t);
				_ms.Position = 0;
				_obj = _ser.ReadObject(_ms);
			}
			catch (Exception)
			{
				_obj = null;
			}
			finally
			{
				if (_ms != null) {
					_ms.Close();
				}
			}
			
			return _obj;
		}
	}
}